﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using MoneyManagerNET.Presentation.Infrastructure;
using System.Windows.Markup;

namespace Mvvm.Infrastructure
{
    public static class ViewModelBinder
    {


        /// <summary>
        /// The default DataTemplate used for ItemsControls when required.
        /// </summary>
        public static DataTemplate DefaultItemTemplate = (DataTemplate)
#if SILVERLIGHT
        XamlReader.Load(
#else
XamlReader.Parse(
#endif
"<DataTemplate xmlns='http://schemas.microsoft.com/winfx/2006/xaml/presentation' " +
                          "xmlns:mvvm='clr-namespace: Mvvm.Infrastructure;assembly=Mvvm.Infrastructure'> " +
                "<ContentControl mvvm:View.Model=\"{Binding}\" VerticalContentAlignment=\"Stretch\" HorizontalContentAlignment=\"Stretch\" IsTabStop=\"False\" />" +
            "</DataTemplate>"
            );


        static Dictionary<Type, DependencyProperty> _boundProperties = new Dictionary<Type, DependencyProperty>()
        {
            {typeof(TextBox),TextBox.TextProperty},
            {typeof(ItemsControl),ItemsControl.ItemsSourceProperty},
            {typeof(TextBlock),TextBlock.TextProperty},
            {typeof(Border),Border.VisibilityProperty},
            {typeof(Button),Button.ContentProperty}
        };

        public static void Bind(object viewModel, DependencyObject view) {
            var element = view as FrameworkElement;
            if (element == null)
                return;

            var viewType = viewModel.GetType();
            var properties = viewType.GetProperties();
            var methods = viewType.GetMethods();

            BindCommands(viewModel, element, methods, properties);
            BindProperties(element, properties);

            element.DataContext = viewModel;
        }

        public static string s_DateFormat = "{0:MM/dd/yyyy}";
        static BooleanToVisibilityConverter s_booleanToVisibilityConverter = new BooleanToVisibilityConverter();
        private static void BindProperties(FrameworkElement view, System.Reflection.PropertyInfo[] properties)
        {
            foreach (var property in properties)
            {
                var foundControl = view.FindName(property.Name) as DependencyObject;
                if (foundControl == null)
                    continue;

                DependencyProperty boundProperty;
                if (!_boundProperties.TryGetValue(foundControl.GetType(), out boundProperty))
                    continue;

                if (((FrameworkElement)foundControl).GetBindingExpression(boundProperty) != null)
                    continue;

                var binding = new Binding (property.Name){
                    Mode=property.CanWrite?BindingMode.TwoWay:BindingMode.OneWay,
                    //ValidatesOnDataErrors=Attribute.GetCustomAttributes(property,typeof(ValidationAttribute)).Any();
                };

                if(boundProperty==UIElement.VisibilityProperty&&typeof(bool).IsAssignableFrom(property.PropertyType))
                    binding.Converter=s_booleanToVisibilityConverter;
                else if(typeof(DateTime).IsAssignableFrom(property.PropertyType))
                    binding.StringFormat=s_DateFormat;

                BindingOperations.SetBinding(foundControl,boundProperty,binding);

                var textbox=foundControl as TextBox;
                if(textbox!=null&&boundProperty==TextBox.TextProperty){
                    textbox.TextChanged+=delegate{textbox.GetBindingExpression(TextBox.TextProperty).UpdateSource();};
                    continue;
                }

                var itemsControl=foundControl as ItemsControl;
                if(itemsControl!=null&&string.IsNullOrEmpty(itemsControl.DisplayMemberPath)&& itemsControl.ItemTemplate!=null){
                    //TODO:31:30
                    itemsControl.ItemTemplate = DefaultItemTemplate;
                }

            }
        }

        private static void BindCommands(object viewModel, FrameworkElement view, System.Reflection.MethodInfo[] methods, System.Reflection.PropertyInfo[] properties)
        {
            foreach (var method in methods)
            {
                var foundControl = view.FindName(method.Name);
                if (foundControl == null)
                    continue;

                var foundProperty = properties.FirstOrDefault(x=>x.Name=="Can"+method.Name);

               //- var cmd = new DelegateCommand();\
                //TODO
            }
        }
    }
}
